package jz.joyoung.robot.util;

import android.util.Base64;

import java.nio.charset.StandardCharsets;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * <p>
 * 功能：AES128位对称加密类，该类参数需要16位字符串秘钥及待加/解密字符串
 * <br/>参考文章：
 * http://blog.csdn.net/coyote1994/article/details/52368921
 * <br/>http://jueyue.iteye.com/blog/1830792
 * </p>
 *
 * @version V1.0
 * @ClassName: AES128
 */
public class AES128 {
    /**
     * 定义一个初始向量，需要与iOS端的统一，使用CBC模式，需要一个向量iv，可增加加密算法的强度
     */
    private static final String IV_STRING = "16-Bytes--String";


    /**
     * <p class="detail">
     * 功能：AES128加密方法
     * </p>
     *
     * @param content 待加密内容
     * @param key     加密密钥（16位字符串）
     * @return 加密后的字符串（结果已经过base64加密）
     * @throws Exception
     * @author LZG
     * @date 2018年8月23日
     */
    public static String encryptStringAES(String content, String key) throws Exception {
        byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
        // 注意，为了能与 iOS 统一
        // 这里的 key 不可以使用 KeyGenerator、SecureRandom、SecretKey 生成
        byte[] enCodeFormat = key.getBytes();
        SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
        byte[] initParam = IV_STRING.getBytes();
        IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
        // 指定加密的算法、工作模式和填充方式
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        byte[] encryptedBytes = cipher.doFinal(byteContent);
        // 同样对加密后数据进行 base64 编码
        return Base64.encodeToString(encryptedBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
    }

    /**
     * <p class="detail">
     * 功能：AES128加密方法
     * </p>
     *
     * @param content 待加密内容
     * @param key     加密密钥（16位字符串）
     * @return 加密后的字符串（结果已经过base64加密）
     * @throws Exception
     * @author LZG
     * @date 2018年8月23日
     */
    public static byte[] encryptByteAES(String content, String key)
            throws Exception {
        byte[] byteContent = content.getBytes(StandardCharsets.UTF_8);
        // 注意，为了能与 iOS 统一
        // 这里的 key 不可以使用 KeyGenerator、SecureRandom、SecretKey 生成
        byte[] enCodeFormat = key.getBytes();
        SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, "AES");
        byte[] initParam = IV_STRING.getBytes();
        IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
        // 指定加密的算法、工作模式和填充方式
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        byte[] encryptedBytes = cipher.doFinal(byteContent);
        // 同样对加密后数据进行 base64 编码
        return Base64.decode(encryptedBytes, Base64.DEFAULT);
    }

    /**
     * <p class="detail">
     * 功能：解密函数
     * </p>
     *
     * @param content 待解密字符串
     * @param key     解密秘钥（16位字符串，需要与加密字符串一致）
     * @return
     * @throws Exception
     * @author LZG
     * @date 2018年8月23日
     */
    public static String decryptByteAES(byte[] content, String key)
            throws Exception {
        // 先base64 解码
        byte[] encryptedBytes = Base64.decode(content, Base64.DEFAULT);
        byte[] enCodeFormat = key.getBytes();
        SecretKeySpec secretKey = new SecretKeySpec(enCodeFormat, "AES");
        byte[] initParam = IV_STRING.getBytes();//使用CBC模式，需要一个向量iv，可增加加密算法的强度
        IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//"算法/模式/补码方式"
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
        byte[] result = cipher.doFinal(encryptedBytes);
        return new String(result, StandardCharsets.UTF_8);
    }
}
